package com.audaque.springboot.foshanupload.web.webdemo.controller;

import com.audaque.springboot.foshanupload.core.config.ThreadConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@RestController
@RequestMapping("memory")
public class MemoryController {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    /**
     * 线程池，大小1
     */
    private static ExecutorService executorService = Executors.newFixedThreadPool(1);
    //静态：全局
    private static HashMap<Object, Object> myMap = new HashMap<>();

    private static final int size = 1024 * 1024 * 2;

    private static final int BUFFER = 1024 * 1024 * 1024;//1GB


    @RequestMapping("directMemoryOver")
    public void directMemoryOver() {

        new Thread(() -> {
            ArrayList<ByteBuffer> list = new ArrayList<>();
            while (true) {
                //OutOfMemoryError: Direct buffer memory:直接内存溢出
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
            }
        }).start();

        //不受影响
        new Thread(() -> {
            List<byte[]> list = new ArrayList<>();
            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                list.add(new byte[size]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //不受影响
        new Thread(() -> {

            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }



    @RequestMapping("memoryOverFlow")
    public void memoryOverFlow() {
        //OutOfMemoryError: Java heap space:堆溢出，线程结束，回收内存
        new Thread(() -> {
            List<byte[]> list = new ArrayList<>();
            while (true) {
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                list.add(new byte[size]);

            }

        }).start();


        //不受影响
        new Thread(() -> {
            List<byte[]> list = new ArrayList<>();
            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                list.add(new byte[size]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


        new Thread(() -> {
            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }


    /**
     * 死循环，持续向HashMap里塞数据，由于myMap属于GCRoots，始终得不到释放，所以它最终的结果就是OOM。
     */
    @RequestMapping("gcRootOverFlow")
    public void gcRootOverFlow() {

        //OutOfMemoryError: Java heap space:全局堆溢出，属于内存泄漏，线程结束，回收无法内存
        new Thread(() -> {
            Long counter = 0L;
            while (true) {
                myMap.put("key" + counter++, new byte[size]);
            }

        }).start();


        //受影响，要求的内存给不到，接着报OutOfMemoryError: Java heap space
        new Thread(() -> {
            List<byte[]> list = new ArrayList<>();
            while (true) {
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                list.add(new byte[size]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(() -> {
            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }

    /**
     * 如果你忘记了重写对象的hashCode和equals方法，就会产生内存泄漏。
     */
    public static class Key {
        String title;

        public Key(String title) {
            this.title = title;
        }

    }

    /**
     * 内存泄漏
     */
    @RequestMapping("memoryLeak")
    public void memoryLeak() {
        Map<Key, Integer> map = new HashMap<>();
        map.put(new Key("1"), 1);
        map.put(new Key("2"), 2);
        map.put(new Key("3"), 2);
        Integer integer = map.get(new Key("2"));
        System.out.println(integer);
    }

    @RequestMapping("constantPoolOver")
    public void constantPoolOver() {
        new Thread(() -> {
            while (true) {
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
            }
        }).start();
        new Thread(() -> {
            // 使用Set保持着常量池引用，避免Full GC回收常量池行为
            //OutOfMemoryError:GC overhead limit exceeded
            Set<String> set = new HashSet<String>();
            short i = 0;
            while (true) {
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                //从正到负再到正
                set.add(String.valueOf(i++).intern());
                log.debug("i:" + i);

            }
        }).start();
    }


    @RequestMapping("functionAreaOver")
    public void functionAreaOver() {
        new Thread(() -> {
            while (true) {
               // OutOfMemoryError-->Metaspace
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMOBJECT.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, null);
                    }
                });
                enhancer.create();
            }
        }).start();


        //不受影响
        new Thread(() -> {
            List<byte[]> list = new ArrayList<>();
            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                list.add(new byte[size]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //不受影响
        new Thread(() -> {

            while (true) {
                //打断点依然可以进来
                System.out.println(new Date().toString() + Thread.currentThread() + "**");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();



    }

    static class OOMOBJECT {


    }


}
